在前面ADO.NET Mapping例子可以發現嚴重問題「沒辦法多類別共用方法,每新增一個類別就需要重寫代碼」
。要解決這個問題,可以寫一個共用方法在Runtime時期針對不同的類別做不同的邏輯處理。
實作方式做主要有三種Reflection、Expression、Emit,這邊首先介紹最簡單方式:「Reflection」,我這邊會使用反射方式從零模擬Query寫代碼,讓讀者初步了解動態處理概念。(假如有經驗的讀者可以跳過本篇)
邏輯 :
泛型的條件約束new()
達到動態建立物件屬性字串名稱當Key
,可以使用Reflection取得動態類別的屬性名稱,在藉由DataReader this[string parameter]
取得資料庫資料最後得到以下代碼 :
public static class DemoExtension
{
public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql) where T : new()
{
using (var command = cnn.CreateCommand())
{
command.CommandText = sql;
using (var reader = command.ExecuteReader())
while (reader.Read())
yield return reader.CastToType<T>();
}
}
//1.使用泛型傳遞動態類別
private static T CastToType<T>(this IDataReader reader) where T : new()
{
//2.使用泛型的條件約束new()達到動態建立物件
var instance = new T();
//3.DataReader需要使用屬性字串名稱當Key,可以使用Reflection取得動態類別的屬性名稱,在藉由DataReader this[string parameter]取得資料庫資料
var type = typeof(T);
var props = type.GetProperties();
foreach (var p in props)
{
var val = reader[p.Name];
//4.使用PropertyInfo.SetValue方式動態將資料庫資料賦予物件
if( !(val is System.DBNull) )
p.SetValue(instance, val);
}
return instance;
}
}
Reflection版本優點是代碼簡單
,但它有以下問題
「查多少用多少,不浪費」
(這段之後講解)。「查表法 + 動態建立方法」
以空間換取時間。GetOrdinal
方法,可以查看MSDN官方解釋,效率比Index取值差
。